home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1 / Nebula One.iso / Internet / WWW / analog / Source / output.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-02-07  |  53.0 KB  |  2,068 lines

  1. /*** analog 1.9beta ***/
  2. /* Please read Readme.html, or http://www.statslab.cam.ac.uk/~sret1/analog/  */
  3.  
  4. /*** output.c; the output functions, obviously. ***/
  5.  
  6. #include "analhea2.h"
  7.  
  8. /* A few variables global to this file */
  9. int total_succ_reqs, total_fail_reqs, total_other_reqs;
  10. int total_succ_reqs7, total_fail_reqs7, total_other_reqs7;
  11.  
  12. /*** The first function prints the "goto" line; links to all reports except
  13.      possibly one (the one we're on). If called gotos('\0') won't omit one.
  14.      If called gotos('z') will omit 'Top'. ***/
  15.  
  16. void gotos(FILE *outf, char c)
  17. {
  18.   extern char reportorder[];
  19.   extern flag bq, Bq, cq, dq, Dq, eq, fq, hq, Hq, iq, mq, oq, rq, Sq, Wq, xq;
  20.  
  21.   char *i;
  22.  
  23.   if (xq) {
  24.     fprintf(outf, "\n\n<p>(<b>Go To</b>");
  25.  
  26.     if (c != 'z')
  27.       fprintf(outf, ": <a HREF=\"#Top\">Top</a>");
  28.  
  29.     for (i = reportorder; *i != '\0'; i++) {
  30.       if (c != *i) {   /* o/wise we don't want this one */
  31.     switch(*i) {
  32.     case 'b':
  33.       if (bq)
  34.         fprintf(outf, ": <a HREF=\"#Browser\">Browser summary</a>");
  35.       break;
  36.     case 'B':
  37.       if (Bq)
  38.         fprintf(outf, ": <a HREF=\"#FullBrowser\">Browser report</a>");
  39.       break;
  40.     case 'c':
  41.       if (cq)
  42.         fprintf(outf, ": <a HREF=\"#Status\">Status code report</a>");
  43.       break;
  44.     case 'd':
  45.       if (dq)
  46.         fprintf(outf, ": <a HREF=\"#Daily\">Daily summary</a>");
  47.       break;
  48.     case 'D':
  49.       if (Dq)
  50.         fprintf(outf, ": <a HREF=\"#FullDaily\">Daily report</a>");
  51.       break;
  52.     case 'e':
  53.       if (eq)
  54.         fprintf(outf, ": <a HREF=\"#Error\">Error report</a>");
  55.       break;
  56.     case 'f':
  57.       if (fq)
  58.         fprintf(outf, ": <a HREF=\"#Referer\">Referer report</a>");
  59.       break;
  60.     case 'H':
  61.       if (Hq)
  62.         fprintf(outf, ": <a HREF=\"#FullHourly\">Hourly report</a>");
  63.       break;
  64.     case 'h':
  65.       if (hq)
  66.         fprintf(outf, ": <a HREF=\"#Hourly\">Hourly summary</a>");
  67.       break;
  68.     case 'i':
  69.       if (iq)
  70.         fprintf(outf, ": <a HREF=\"#Directory\">Directory report</a>");
  71.       break;
  72.     case 'm':
  73.       if (mq)
  74.         fprintf(outf, ": <a HREF=\"#Monthly\">Monthly report</a>");
  75.       break;
  76.     case 'o':
  77.       if (oq)
  78.         fprintf(outf, ": <a HREF=\"#Domain\">Domain report</a>");
  79.       break;
  80.     case 'r':
  81.       if (rq)
  82.         fprintf(outf, ": <a HREF=\"#Request\">Request report</a>");
  83.       break;
  84.     case 'S':
  85.       if (Sq)
  86.         fprintf(outf, ": <a HREF=\"#Host\">Host report</a>");
  87.       break;
  88.     case 'W':
  89.       if (Wq)
  90.         fprintf(outf, ": <a HREF=\"#Weekly\">Weekly report</a>");
  91.       break;
  92.  
  93.     }   /* end switch */
  94.       }     /* end if this i wanted */
  95.     }       /* end for i */
  96.  
  97.     fprintf(outf, ")\n");
  98.  
  99.   }         /* end if xq */
  100. }           /* end function gotos() */
  101.  
  102. /*** Next, to print strings with HTML reserved characters translated ***/
  103.  
  104. void htmlputc(char c, FILE *outf)
  105. {
  106.   if (c == '<')
  107.     fprintf(outf, "<");
  108.   else if (c == '>')
  109.     fprintf(outf, ">");
  110.   else if (c == '&')
  111.     fprintf(outf, "&");
  112.   else if (c == '"')
  113.     fprintf(outf, """);
  114.   else
  115.     putc(c, outf);
  116. }
  117.  
  118. void htmlfprintf(FILE *outf, char string[MAXSTRINGLENGTH])
  119. {
  120.   char *c;
  121.  
  122.   for (c = string; *c != '\0'; c++)
  123.     htmlputc(*c, outf);
  124.  
  125. }
  126.  
  127. /*** Now a little routine to find the correct divider for large numbers of
  128.      bytes. Also sets bprefix[0] as a side effect. ***/
  129.  
  130. double finddivider(double bytes, char *bprefix)
  131. {
  132.   extern flag rawbytes;
  133.  
  134.   double bdivider;
  135.  
  136.   if (rawbytes)
  137.     bdivider = 1.0;
  138.   else
  139.     for (bdivider = 1; bytes / bdivider >= 999999.5;
  140.      bdivider *= 1024)
  141.       ;  /* run bdivider to right multiplier */
  142.  
  143.   if (bdivider == 1.0)
  144.     *bprefix = '\0';
  145.   else if (bdivider == 1024.0)
  146.     *bprefix = 'k';
  147.   else if (bdivider == 1048576.0)
  148.     *bprefix = 'M';
  149.   else if (bdivider == 1073741824.0)
  150.     *bprefix = 'G';
  151.   else if (bdivider == 1099511627776.0)
  152.     *bprefix = 'T';
  153.   else       /* 10^6 terabytes should be enough. Just about. */
  154.     *bprefix = '?';
  155.  
  156.   return(bdivider);
  157. }
  158.  
  159. /*** print a line across the page, assuming ASCII mode ***/
  160.  
  161. void asciiline(FILE *outf)
  162. {
  163.   extern int pagewidth;
  164.  
  165.   int i;
  166.  
  167.   for (i = 0; i < pagewidth; i++)
  168.     fprintf(outf, "-");
  169.   fprintf(outf, "\n\n");
  170. }
  171.  
  172. /*** a barchart bar, length n, within <pre><tt> ***/
  173.  
  174. void barplot(FILE *outf, int n)
  175. {
  176.   extern int aq;
  177.   extern flag graphical;
  178.   extern char imagedir[];
  179.   extern char markchar;
  180.  
  181.   int i, k;
  182.   flag first = TRUE;
  183.  
  184.   if (aq || !graphical) {
  185.     for ( ; n > 0; n--)
  186.       fprintf(outf, "%c", markchar);
  187.   }
  188.  
  189.   else {
  190.     for (k = 32; k >= 1; k /= 2) {
  191.       while (n >= k) {
  192.     fprintf(outf, "<img src=\"");
  193.     htmlfprintf(outf, imagedir);
  194.     fprintf(outf, "bar%d.gif\" alt=\"", k);
  195.     if (first) {
  196.       for (i = n; i > 0; i--)
  197.         htmlputc(markchar, outf);
  198.       first = FALSE;
  199.     }
  200.     fprintf(outf, "\">");
  201.     n -= k;
  202.       }
  203.     }
  204.   }
  205. }
  206.  
  207. /*** A nasty header bit. Return rough floor -- accurate if negative. ***/
  208.  
  209. int whatincluded(FILE *outf, int sortby, char *minreqstr, char *minbytestr,
  210.          char singular[20], char plural[21], flag subdoms)
  211. {
  212.   extern double bytefloor();         /* in hash.c */
  213.   extern int reqfloor();             /* in hash.c */
  214.   extern void doublefprintf();       /* in utils.c */
  215.  
  216.   extern double total_bytes;
  217.  
  218.   int genfloor;
  219.   int tempint;
  220.   char tempc;
  221.  
  222.   if (sortby == BYBYTES) {
  223.     if (minbytestr[0] == '-') {
  224.       genfloor = (int)bytefloor(total_bytes, minbytestr);
  225.       if (genfloor == -1)
  226.     fprintf(outf, "Printing the first %s", singular);
  227.       else
  228.     fprintf(outf, "Printing the first %d %s", -genfloor, plural);
  229.     }
  230.     else {
  231.       fprintf(outf, "Printing all %s", plural);
  232.       genfloor = (int)(ceil(bytefloor(total_bytes, minbytestr)));
  233.       if (genfloor > 0) {
  234.     fprintf(outf, " with at least ");
  235.     tempint = MAX((int)strlen(minbytestr) - 1, 0);
  236.     if (minbytestr[tempint] == '%') {
  237.       minbytestr[tempint] = '\0';
  238.       doublefprintf(outf, atof(minbytestr));
  239.       fprintf(outf, "%% of the traffic");
  240.     }
  241.     else if (minbytestr[tempint] == 'k' || minbytestr[tempint] == 'M' ||
  242.          minbytestr[tempint] == 'G' || minbytestr[tempint] == 'T') {
  243.       tempc = minbytestr[tempint];
  244.       minbytestr[tempint] = '\0';
  245.       doublefprintf(outf, atof(minbytestr));
  246.       fprintf(outf, " %cbytes of traffic", tempc);
  247.     }
  248.     else {
  249.       doublefprintf(outf, atof(minbytestr));
  250.       fprintf(outf, " bytes of traffic");
  251.     }
  252.       }
  253.     }
  254.     if (subdoms)
  255.       fprintf(outf, ".\n");
  256.     else
  257.       fprintf(outf, ",%ssorted by amount of traffic.\n",
  258.           (genfloor > 0)?"\n  ":" ");
  259.   }
  260.   else {   /* sortby not BYBYTES */
  261.     genfloor = reqfloor(total_succ_reqs, minreqstr);
  262.     if (minreqstr[0] == '-') {
  263.       if (genfloor == -1)
  264.     fprintf(outf, "Printing the first %s", singular);
  265.       else
  266.     fprintf(outf, "Printing the first %d %s", -genfloor, plural);
  267.     }
  268.     else {
  269.       fprintf(outf, "Printing all %s", plural);
  270.       if (genfloor > 0) {
  271.     fprintf(outf, " with at least ");
  272.     tempint = MAX((int)strlen(minreqstr) - 1, 0);
  273.     if (minreqstr[tempint] == '%') {
  274.       minreqstr[tempint] = '\0';
  275.       doublefprintf(outf, atof(minreqstr));
  276.       fprintf(outf, "%% of the requests");
  277.     }
  278.     else
  279.       fprintf(outf, "%d request%s", atoi(minreqstr),
  280.           atoi(minreqstr) == 1?"":"s");
  281.       }
  282.     }
  283.     if (subdoms)
  284.       fprintf(outf, ".\n");
  285.     else if (sortby == BYREQUESTS)
  286.       fprintf(outf, ",%ssorted by number of requests.\n",
  287.           (genfloor > 0)?"\n  ":" ");
  288.     else if (sortby == ALPHABETICAL)
  289.       fprintf(outf, ",%ssorted alphabetically.\n", (genfloor > 0)?"\n  ":" ");
  290.     else
  291.       fprintf(outf, ", unsorted.\n");
  292.   }
  293.  
  294.   return(genfloor);
  295.  
  296. }
  297.  
  298.  
  299. /*** Generic output function for generic objects ***/
  300.  
  301. void genout(FILE *outf, struct genstruct *sorthead, int sortby,
  302.         char *minreqstr, char *minbytestr, int max_reqs, double max_bytes,
  303.         char *wantcols, char anchor[10], char title[17], char singular[13],
  304.         char plural[14], char codeletter, flag alphahost,
  305.         /* alphabetical host sort? */   flag byq, int kq, /* pagelinks? */
  306.         char baseurl[MAXSTRINGLENGTH]) {
  307.  
  308.   extern char *reversehostname();    /* in alias.c */
  309.   extern flag included();            /* in alias.c */
  310.  
  311.   extern int pagewidth;
  312.   extern int dirlevel;
  313.   extern int host_max_length;
  314.   extern int aq;
  315.   extern flag rawbytes;
  316.   extern double total_bytes;
  317.   extern struct include *ispagehead;
  318.  
  319.   struct genstruct *p;
  320.   int fieldwidth, bfieldwidth, graphwidth;
  321.   int genfloor;
  322.   double bdivider;
  323.   char bprefix[2];
  324.   char *cols;
  325.   double pc;
  326.   int pc1, pc2;
  327.   int i, j, tempint;
  328.   char *tempc;
  329.   
  330.   bprefix[0] = '\0';
  331.   bprefix[1] = '\0';
  332.  
  333.   if (!aq) {
  334.     fprintf(outf,
  335.         "\n\n<hr>\n<h2><a NAME=\"%s\">%s</a></h2>\n\n", anchor, title);
  336.     gotos(outf, codeletter);
  337.     fprintf(outf, "<p>");
  338.   }
  339.   else {
  340.     fprintf(outf, "%s\n", title);
  341.     for (tempc = title; *tempc != '\0'; tempc++)
  342.       fprintf(outf, "-");
  343.     fprintf(outf, "\n");
  344.   }
  345.  
  346.   genfloor = whatincluded(outf, sortby, minreqstr, minbytestr, singular,
  347.               plural, FALSE);
  348.   if (codeletter == 'i') {
  349.     if (!aq)
  350.       fprintf(outf, "<br>");
  351.     fprintf(outf, "Printing directories to depth %d.\n", dirlevel);
  352.   }
  353.  
  354.   if (aq)
  355.     fprintf(outf, "\n");
  356.   else
  357.     fprintf(outf, "<pre>");
  358.  
  359.  
  360.   tempint = 10000;
  361.   for (fieldwidth = 5; max_reqs / tempint >= 10; fieldwidth++)
  362.     tempint *= 10;
  363.  
  364.   if (byq) {
  365.     if (rawbytes) {
  366.       tempint = 100000;
  367.       for (bfieldwidth = 6; max_bytes / tempint >= 10; bfieldwidth++)
  368.     tempint *= 10;
  369.     }
  370.     else
  371.       bfieldwidth = 6;
  372.  
  373.     bdivider = finddivider(max_bytes, bprefix);
  374.   }
  375.  
  376.   for (cols = wantcols; *cols != '\0'; cols++) {
  377.     switch(*cols) {
  378.     case 'R':
  379.       for (i = 5; i < fieldwidth; i++)
  380.     fprintf(outf, " ");
  381.       fprintf(outf, "#reqs: ");
  382.       break;
  383.     case 'r':
  384.       fprintf(outf, " %%reqs: ");
  385.       break;
  386.     case 'B':
  387.       if (byq) {
  388.     for (i = 6; i < bfieldwidth; i++)
  389.       fprintf(outf, " ");
  390.     fprintf(outf, "%sbytes: ", bprefix[0] == '\0'?" ":bprefix);
  391.       }
  392.       break;
  393.     case 'b':
  394.       if (byq)
  395.     fprintf(outf, "%%bytes: ");
  396.       break;
  397.     }
  398.   }
  399.   fprintf(outf, "%s\n", singular);
  400.   
  401.   for (cols = wantcols; *cols != '\0'; cols++) {
  402.     switch(*cols) {
  403.     case 'R':
  404.       for (i = 1; i <= fieldwidth; i++)
  405.     fprintf(outf, "-");
  406.       fprintf(outf, "  ");
  407.       break;
  408.     case 'r':
  409.       fprintf(outf, "------  ");
  410.       break;
  411.     case 'B':
  412.       if (byq) {
  413.     for (i = 1; i <= bfieldwidth; i++)
  414.       fprintf(outf, "-");
  415.     fprintf(outf, "  ");
  416.       }
  417.       break;
  418.     case 'b':
  419.       if (byq)
  420.     fprintf(outf, "------  ");
  421.       break;
  422.     }
  423.   }
  424.   for (tempc = singular; *tempc != '\0'; tempc++)
  425.     fprintf(outf, "-");
  426.   fprintf(outf, "\n");
  427.  
  428.   if (genfloor < 0)
  429.     j = genfloor;
  430.   else j = 1;
  431.  
  432.   if (alphahost) {
  433.     graphwidth = pagewidth;
  434.     for (cols = wantcols; *cols != '\0'; cols++) {
  435.       switch(*cols) {
  436.       case 'R':
  437.     graphwidth -= fieldwidth + 2;
  438.     break;
  439.       case 'B':
  440.     graphwidth -= bfieldwidth + 2;
  441.     break;
  442.       case 'r':
  443.       case 'b':
  444.     graphwidth -= 8;
  445.     break;
  446.       }
  447.     }
  448.     graphwidth = MIN(graphwidth, host_max_length);
  449.   }
  450.  
  451.   for(p = sorthead; p -> name != NULL && (j++) != 0;
  452.       p = p -> next) {
  453.  
  454.     for (cols = wantcols; *cols != '\0'; cols++) {
  455.       switch(*cols) {
  456.       case 'R':
  457.     fprintf(outf, "%*d: ", fieldwidth, p -> reqs);
  458.     break;
  459.       case 'r':
  460.     pc = (p -> reqs + 0.0) / ((total_succ_reqs + 0.0) / 10000);
  461.     pc1 = ((int)(pc + 0.5)) / 100;     /* whole no. of %reqs */
  462.     pc2 = ((int)(pc + 0.5)) % 100;     /* remaining 100ths. */
  463.     if (pc1 == 100)
  464.       fprintf(outf, "  100%%: ");
  465.     else if (pc1 > 0 || pc2 > 0)
  466.       fprintf(outf, "%2d.%02d%%: ", pc1, pc2);
  467.     else
  468.       fprintf(outf, "      : ");
  469.     break;
  470.       case 'B':
  471.     if (byq) {
  472.       if (p -> bytes / bdivider > 0.5)
  473.         fprintf(outf, "%*.0lf", bfieldwidth, p -> bytes / bdivider);
  474.       else for (i = 0; i < bfieldwidth; i++)
  475.         fprintf(outf, " ");
  476.       fprintf(outf, ": ");
  477.     }
  478.     break;
  479.       case 'b':
  480.     if (byq) {
  481.       pc = p -> bytes / (total_bytes / 10000);
  482.       pc1 = ((int)(pc + 0.5)) / 100;    /* whole no. of %bytes */
  483.       pc2 = ((int)(pc + 0.5)) % 100;    /* remaining 100ths. */
  484.       if (pc1 == 100)
  485.         fprintf(outf, "  100%%: ");
  486.       else if (pc1 > 0 || pc2 > 0)
  487.         fprintf(outf, "%2d.%02d%%: ", pc1, pc2);
  488.       else
  489.         fprintf(outf, "      : ");
  490.     }
  491.     break;
  492.       }
  493.     }
  494.     
  495.     if (alphahost && !isdigit(p -> name[0])) {  /* we've swapped the names */
  496.       reversehostname(p -> name);
  497.       /* Also in that case right align names */
  498.       for (i = graphwidth - (int)strlen(p -> name); i > 0; i--)
  499.     fprintf(outf, " ");
  500.     }
  501.  
  502.     if ((kq == 2) ||
  503.     /* if we want to link to everything ... */
  504.     (kq == 1 && included(p -> name, ispagehead))) {
  505.       /* or it is a page, and we want to link to pages */
  506.       fprintf(outf, "<a HREF=\"");
  507.       htmlfprintf(outf, baseurl);
  508.       htmlfprintf(outf, p -> name);
  509.       fprintf(outf, "\">");
  510.       htmlfprintf(outf, p -> name);
  511.       fprintf(outf, "</a>");
  512.     }
  513.     else   /* (the usual case for most reports) */
  514.       if (!aq)
  515.     htmlfprintf(outf, p -> name);
  516.       else
  517.     fprintf(outf, p -> name);
  518.     fprintf(outf, "\n");
  519.  
  520.   }
  521.       
  522.   if (aq)
  523.     asciiline(outf);
  524.   else
  525.     fprintf(outf, "</pre>");
  526.     
  527. }
  528.  
  529. /*** The domain report is similar to the generic ones. It differs in that
  530.      the domains are stored in a different structure, and that subdomains
  531.      must be printed. ***/
  532.  
  533. void domout(FILE *outf, int firstdom)
  534. {
  535.   extern struct domain *domainhead[];
  536.   extern int aq;
  537.   extern flag byq, rawbytes;
  538.   extern int domsortby;
  539.   extern char domminbytestr[], domminreqstr[];
  540.   extern char subdomminbytestr[], subdomminreqstr[];
  541.   extern int dom_max_reqs;
  542.   extern double dom_max_bytes;
  543.   extern int subonumber;
  544.   extern char domcols[];
  545.   extern double total_bytes;
  546.  
  547.   int domfloor;
  548.  
  549.   struct domain *domp;
  550.   double bdivider;
  551.   char bprefix[2];
  552.   char *cols;
  553.   int fieldwidth, bfieldwidth;
  554.   double pc;
  555.   int pc1, pc2;
  556.   int i, j, k, tempint;
  557.   char *tempp;
  558.  
  559.   bprefix[0] = '\0';
  560.   bprefix[1] = '\0';
  561.  
  562.   if (!aq) {
  563.     fprintf(outf,
  564.         "\n\n<hr>\n<h2><a NAME=\"Domain\">Domain Report</a></h2>\n\n");
  565.     gotos(outf, 'o');
  566.   }
  567.   else {
  568.     fprintf(outf, "Domain Report\n");
  569.     fprintf(outf, "-------------\n");
  570.   }
  571.   
  572.   if (!aq)
  573.     fprintf(outf, "<p>");
  574.  
  575.   domfloor = whatincluded(outf, domsortby, domminreqstr, domminbytestr,
  576.               "domain", "domains", FALSE);
  577.   if (subonumber > 0) {
  578.     if (!aq)
  579.       fprintf(outf, "<br>");
  580.     whatincluded(outf, domsortby, subdomminreqstr, subdomminbytestr,
  581.          "requested subdomain", "requested subdomains", TRUE);
  582.   }
  583.  
  584.   if (aq)
  585.     fprintf(outf, "\n");
  586.   else
  587.     fprintf(outf, "<pre>");
  588.   
  589.   tempint = 10000;
  590.   for (fieldwidth = 5; dom_max_reqs / tempint >= 10; fieldwidth++)
  591.     tempint *= 10;
  592.   
  593.   if (byq) {
  594.     if (rawbytes) {
  595.       tempint = 100000;
  596.       for (bfieldwidth = 6; dom_max_bytes / tempint >= 10; bfieldwidth++)
  597.     tempint *= 10;
  598.     }
  599.     else
  600.       bfieldwidth = 6;
  601.  
  602.     bdivider = finddivider(dom_max_bytes, bprefix);
  603.   }
  604.   
  605.   for (cols = domcols; *cols != '\0'; cols++) {
  606.     switch(*cols) {
  607.     case 'R':
  608.       for (i = 5; i < fieldwidth; i++)
  609.     fprintf(outf, " ");
  610.       if (subonumber > 0)
  611.     fprintf(outf, " #reqs : ");
  612.       else
  613.     fprintf(outf, "#reqs: ");
  614.       break;
  615.     case 'r':
  616.       if (subonumber > 0)
  617.     fprintf(outf, "  %%reqs : ");
  618.       else
  619.     fprintf(outf, " %%reqs: ");
  620.       break;
  621.     case 'B':
  622.       if (byq) {
  623.     for (i = 6; i < bfieldwidth; i++)
  624.       fprintf(outf, " ");
  625.     if (subonumber > 0)
  626.       fprintf(outf, " %sbytes : ", bprefix[0] == '\0'?" ":bprefix);
  627.     else
  628.       fprintf(outf, "%sbytes: ", bprefix[0] == '\0'?" ":bprefix);
  629.       }
  630.       break;
  631.     case 'b':
  632.       if (byq) {
  633.     if (subonumber > 0)
  634.       fprintf(outf, " %%bytes : ");
  635.     else
  636.       fprintf(outf, "%%bytes: ");
  637.       }
  638.       break;
  639.     }
  640.   }
  641.   fprintf(outf, "domain\n");
  642.  
  643.   for (cols = domcols; *cols != '\0'; cols++) {
  644.     switch(*cols) {
  645.     case 'R':
  646.       for (i = 1; i <= fieldwidth; i++)
  647.     fprintf(outf, "-");
  648.       if (subonumber > 0)
  649.     fprintf(outf, "--");
  650.       fprintf(outf, "  ");
  651.       break;
  652.     case 'r':
  653.       if (subonumber > 0)
  654.     fprintf(outf, "--");
  655.       fprintf(outf, "------  ");
  656.       break;
  657.     case 'B':
  658.       if (byq) {
  659.     for (i = 1; i <= bfieldwidth; i++)
  660.       fprintf(outf, "-");
  661.     if (subonumber > 0)
  662.       fprintf(outf, "--");
  663.     fprintf(outf, "  ");
  664.       }
  665.       break;
  666.     case 'b':
  667.       if (byq) {
  668.     if (subonumber > 0)
  669.       fprintf(outf, "--");
  670.     fprintf(outf, "------  ");
  671.       }
  672.         break;
  673.     }
  674.  } 
  675.   fprintf(outf, "------\n");
  676.  
  677.   if (domfloor < 0)
  678.     j = domfloor;
  679.   else j = 1;
  680.  
  681.   for (i = firstdom; i >= 0 && (j++) != 0; i = domainhead[i] -> nexti) {
  682.  
  683.     if (!(i == DOMHASHSIZE - 2 && domainhead[i] -> reqs == -1)) {
  684.  
  685.       for (cols = domcols; *cols != '\0'; cols++) {
  686.     switch(*cols) {
  687.     case 'R':
  688.       if (subonumber > 0)
  689.         fprintf(outf, " %*d : ", fieldwidth,
  690.             domainhead[i] -> reqs);
  691.       else
  692.         fprintf(outf, "%*d: ", fieldwidth, domainhead[i] -> reqs);
  693.       break;
  694.     case 'r':
  695.       pc = (domainhead[i] -> reqs + 0.0) / 
  696.         ((total_succ_reqs + 0.0) / 10000);
  697.       pc1 = ((int)(pc + 0.5)) / 100;     /* whole no. of %reqs */
  698.       pc2 = ((int)(pc + 0.5)) % 100;     /* remaining 100ths. */
  699.       if (subonumber > 0)
  700.         fprintf(outf, " ");
  701.       if (pc1 == 100)
  702.         fprintf(outf, "  100%%");
  703.       else if (pc1 > 0 || pc2 > 0)
  704.         fprintf(outf, "%2d.%02d%%", pc1, pc2);
  705.       else
  706.         fprintf(outf, "      ");
  707.       if (subonumber > 0)
  708.         fprintf(outf, " : ");
  709.       else
  710.         fprintf(outf, ": ");
  711.       break;
  712.     case 'B':
  713.       if (byq) {
  714.         if (domainhead[i] -> bytes / bdivider > 0.5) {
  715.           if (subonumber > 0)
  716.         fprintf(outf, " %*.0lf ", bfieldwidth,
  717.             domainhead[i] -> bytes / bdivider);
  718.           else
  719.         fprintf(outf, "%*.0lf", bfieldwidth,
  720.             domainhead[i] -> bytes / bdivider);
  721.         }
  722.         else for (k = 0; k < bfieldwidth + 2 * (subonumber > 0); k++)
  723.         fprintf(outf, " ");
  724.         fprintf(outf, ": ");
  725.       }
  726.       break;
  727.     case 'b':
  728.       if (byq) {
  729.         pc = domainhead[i] -> bytes / (total_bytes / 10000);
  730.         pc1 = ((int)(pc + 0.5)) / 100;    /* whole no. of %bytes */
  731.         pc2 = ((int)(pc + 0.5)) % 100;    /* remaining 100ths. */
  732.         if (subonumber > 0)
  733.           fprintf(outf, " ");
  734.         if (pc1 == 100)
  735.           fprintf(outf, "  100%%");
  736.         else if (pc1 > 0 || pc2 > 0)
  737.           fprintf(outf, "%2d.%02d%%", pc1, pc2);
  738.         else
  739.           fprintf(outf, "      ");
  740.         if (subonumber > 0)
  741.           fprintf(outf, " : ");
  742.         else
  743.           fprintf(outf, ": ");
  744.       }
  745.       break;
  746.     }
  747.       }
  748.       
  749.       if (domainhead[i] -> id[0] == '*')
  750.     /* flagged domains, not real domain names */
  751.     fprintf(outf, "[%s]\n", domainhead[i] -> name);
  752.       else if (domainhead[i] -> name[0] == '?')
  753.     /* real domain, but don't print name */
  754.     fprintf(outf, ".%s\n", domainhead[i] -> id);
  755.       else
  756.     fprintf(outf, ".%s (%s)\n", domainhead[i] -> id,
  757.         domainhead[i] -> name);
  758.       
  759.       /* Now print its subdomains too. */
  760.       
  761.       for (domp = domainhead[i] -> next; domp -> name != NULL;
  762.        domp = domp -> next) {
  763.     
  764.     for (cols = domcols; *cols != '\0'; cols++) {
  765.       switch(*cols) {
  766.       case 'R':
  767.         fprintf(outf, "(%*d): ", fieldwidth, domp -> reqs);
  768.         break;
  769.       case 'r':
  770.         pc = (domp -> reqs + 0.0) /
  771.           ((total_succ_reqs + 0.0) / 10000);
  772.         pc1 = ((int)(pc + 0.5)) / 100;     /* whole no. of %reqs */
  773.         pc2 = ((int)(pc + 0.5)) % 100;     /* remaining 100ths. */
  774.         if (pc1 == 100)
  775.           fprintf(outf, "(  100%%): ");
  776.       else if (pc1 > 0 || pc2 > 0)
  777.         fprintf(outf, "(%2d.%02d%%): ", pc1, pc2);
  778.       else
  779.         fprintf(outf, "        : ");
  780.         break;
  781.       case 'B':
  782.         if (byq) {
  783.           if (domp -> bytes / bdivider > 0.5)
  784.         fprintf(outf, "(%*.0lf)", bfieldwidth,
  785.             domp -> bytes / bdivider);
  786.           else for (k = 0; k < bfieldwidth + 2; k++)
  787.         fprintf(outf, " ");
  788.           fprintf(outf, ": ");
  789.         }
  790.         break;
  791.       case 'b':
  792.         if (byq) {
  793.           pc = domp -> bytes / (total_bytes / 10000);
  794.           pc1 = ((int)(pc + 0.5)) / 100;  /* whole no. of %bytes */
  795.           pc2 = ((int)(pc + 0.5)) % 100;  /* remaining 100ths. */
  796.           if (pc1 == 100)
  797.         fprintf(outf, "(  100%%): ");
  798.           else if (pc1 > 0 || pc2 > 0)
  799.         fprintf(outf, "(%2d.%02d%%): ", pc1, pc2);
  800.           else
  801.         fprintf(outf, "        : ");
  802.         }
  803.         break;
  804.       }
  805.     }
  806.     
  807.     tempp = domp -> id;
  808.     while ((tempp = strchr(tempp, '.')) != NULL) {
  809.       fprintf(outf, "  "); 
  810.       /* print two spaces for each dot in name */
  811.       tempp++;
  812.     }
  813.     if (i == DOMHASHSIZE - 1)
  814.       fprintf(outf, "  ");  /* + 2 more for numerical domains */
  815.     fprintf(outf, "%s", domp -> id);
  816.     
  817.     if (domp -> name[0] != '?')    /* print name */
  818.       fprintf(outf, " (%s)", domp -> name);
  819.     
  820.     fprintf(outf, "\n");
  821.     
  822.       }    /* end for domp */
  823.     
  824.     }
  825.  
  826.   }   /* end for (i = running over domains) */
  827.     
  828.   if (aq)
  829.     asciiline(outf);
  830.   else
  831.     fprintf(outf, "</pre>");
  832.     
  833. }
  834.  
  835. /*** The date reports aren't quite generic enough to combine completely,
  836.      but we can go a long way towards it. ***/
  837. /*** First a function for printing out the headers of a report and finding
  838.      the fieldwidths etc.; then one for printing out each individual line. ***/
  839.  
  840. void datehead(FILE *outf, int maxreq, double maxbytes,
  841.           char *wantcols, char *graphtype, char anchor[11],
  842.           char title[15], char colhead[13], char codeletter,
  843.           int *unit, int *fieldwidth, int *bfieldwidth, int *graphwidth,
  844.           double *bdivider)  /* NB: colhead: inc. leading spaces. */
  845.               /* The last 5 args are returned altered */
  846. {
  847.   extern void int3printf();         /* in utils.c */
  848.  
  849.   extern int aq;
  850.   extern flag byq, rawbytes;
  851.   extern int pagewidth;
  852.   extern char imagedir[];
  853.   extern char markchar;
  854.  
  855.   char *cols;
  856.   char bprefix[2];
  857.   int i, j, tempint;
  858.   char *tempc;
  859.  
  860.   bprefix[0] = '\0';
  861.   bprefix[1] = '\0';
  862.  
  863.   if (*graphtype == 'b')
  864.     *graphtype = 'B';
  865.  
  866.   if (!aq) {
  867.     fprintf(outf, "<hr>\n<h2><a NAME=\"%s\">%s</a></h2>\n", anchor, title);
  868.       gotos(outf, codeletter);
  869.   }
  870.   else {
  871.     fprintf(outf, "%s\n", title);
  872.     for (tempc = title; *tempc != '\0'; tempc++)
  873.       fprintf(outf, "-");
  874.     fprintf(outf, "\n");
  875.   }
  876.     
  877.   tempint = 10000;
  878.   for (*fieldwidth = 5; maxreq / tempint >= 10; (*fieldwidth)++)
  879.     tempint *= 10;   /* so fieldwidth is log_10(maxreq), but >= 5 */
  880.     
  881.   if (byq) {
  882.     if (rawbytes || (*graphtype == 'B' && *unit > 0)) {
  883.       tempint = 100000;
  884.       for (*bfieldwidth = 6; maxbytes / tempint >= 10; (*bfieldwidth)++)
  885.     tempint *= 10;
  886.     }
  887.     else
  888.       *bfieldwidth = 6;
  889.  
  890.     *bdivider = finddivider(maxbytes, bprefix);
  891.   }
  892.  
  893.   if (*unit <= 0) {   /* (o/wise just use the given amount) */
  894.  
  895.     /* Calculate the graphwidth */
  896.     *graphwidth = pagewidth - (int)strlen(colhead) - 2;
  897.     for (cols = wantcols; *cols != '\0'; cols++) {
  898.       switch(*cols) {
  899.       case 'R':
  900.     *graphwidth -= *fieldwidth + 2;
  901.     break;
  902.       case 'B':
  903.     *graphwidth -= *bfieldwidth + 2;
  904.     break;
  905.       case 'r':
  906.       case 'b':
  907.     *graphwidth -= 8;
  908.     break;
  909.       }
  910.     }
  911.     *graphwidth = MAX(*graphwidth, MINGRAPHWIDTH);  /* must be >= MGW wide */
  912.                                       
  913.     if (*graphtype == 'B')
  914.       *unit = (maxbytes - 1) / (*bdivider * *graphwidth);
  915.     else
  916.       *unit = (maxreq - 1) / *graphwidth;
  917.                                /* except we want a 'nice' amount, so ... */
  918.                  /* (Nice amount is 1, 1.5, 2, 2.5, 3, 4, 5, 6, 8 * 10^n */
  919.  
  920.     j = 0;
  921.     while (*unit > 24) {
  922.       *unit /= 10;
  923.       j++;
  924.     }
  925.     if (*unit == 6)
  926.       *unit = 7;
  927.     else if (*unit == 8)
  928.       *unit = 9;
  929.     else if (*unit >= 20)
  930.       *unit = 24;
  931.     else if (*unit >= 15)
  932.       *unit = 19;
  933.     else if (*unit >= 10)
  934.       *unit = 14;
  935.     (*unit)++;
  936.     for (i = 0; i < j; i++) {
  937.       *unit *= 10;
  938.     }
  939.  
  940.   }     /* end if (*unit <= 0) */
  941.  
  942.   else if (*graphtype == 'B') {   /* o/wise unit doesn't make sense */
  943.     *bdivider = 1;
  944.     bprefix[0] = '\0';
  945.   }
  946.  
  947.   if (!aq) {
  948.     fprintf(outf, "\n<p>Each unit (<tt><img src=\"");
  949.     htmlfprintf(outf, imagedir);
  950.     fprintf(outf, "bar1.gif\" alt=\"");
  951.     htmlputc(markchar, outf);
  952.     fprintf(outf, "\"></tt>) represents ");
  953.     int3printf(outf, *unit);
  954.     if (*graphtype == 'B')
  955.       fprintf(outf, " %sbyte%s, or part thereof.", bprefix,
  956.           (*unit == 1)?"":"s");
  957.     else
  958.       fprintf(outf, " request%s.", (*unit == 1)?"":"s, or part thereof");
  959.     fprintf(outf, "\n\n<pre width=%d><tt>\n", pagewidth);
  960.   }
  961.   else {
  962.     fprintf(outf, "\nEach unit (%c) represents ", markchar);
  963.     int3printf(outf, *unit);
  964.     if (*graphtype == 'B')
  965.       fprintf(outf, " %sbyte%s, or part thereof.\n\n", bprefix,
  966.           (*unit == 1)?"":"s");
  967.     else
  968.       fprintf(outf, " request%s.\n\n",
  969.           (*unit == 1)?"":"s, or part thereof");
  970.   }
  971.     
  972.   fprintf(outf, "%s: ", colhead);
  973.   for (cols = wantcols; *cols != '\0'; cols++) {
  974.     switch(*cols) {
  975.     case 'R':
  976.       for (i = 5; i < *fieldwidth; i++)
  977.     fprintf(outf, " ");
  978.       fprintf(outf, "#reqs: ");
  979.       break;
  980.     case 'r':
  981.       fprintf(outf, " %%reqs: ");
  982.       break;
  983.     case 'B':
  984.       if (byq) {
  985.     for (i = 6; i < *bfieldwidth; i++)
  986.       fprintf(outf, " ");
  987.     fprintf(outf, "%sbytes: ", bprefix[0] == '\0'?" ":bprefix);
  988.       }
  989.       break;
  990.     case 'b':
  991.       if (byq)
  992.     fprintf(outf, "%%bytes: ");
  993.       break;
  994.     }
  995.   }
  996.  
  997.   fprintf(outf, "\n");
  998.   for (tempc = colhead; *tempc != '\0'; tempc++)
  999.     fprintf(outf, "-");
  1000.   fprintf(outf, "  ");
  1001.   for (cols = wantcols; *cols != '\0'; cols++) {
  1002.     switch(*cols) {
  1003.     case 'R':
  1004.       for (i = 1; i <= *fieldwidth; i++)
  1005.     fprintf(outf, "-");
  1006.       fprintf(outf, "  ");
  1007.       break;
  1008.     case 'r':
  1009.       fprintf(outf, "------  ");
  1010.       break;
  1011.     case 'B':
  1012.       if (byq) {
  1013.     for (i = 1; i <= *bfieldwidth; i++)
  1014.       fprintf(outf, "-");
  1015.     fprintf(outf, "  ");
  1016.       }
  1017.       break;
  1018.     case 'b':
  1019.       if (byq)
  1020.     fprintf(outf, "------  ");
  1021.       break;
  1022.     }
  1023.   }
  1024.   fprintf(outf, "\n");
  1025. }
  1026.  
  1027. /* As promised, each separate line. We print name of date in output() though */
  1028.  
  1029. void dateline(FILE *outf, int reqs, double bytes, char *wantcols,
  1030.           char graphtype, int fieldwidth, int bfieldwidth,
  1031.           int unit, int bdivider) {
  1032.   extern double total_bytes;
  1033.   extern flag byq;
  1034.  
  1035.   char *cols;
  1036.   double pc;
  1037.   int pc1, pc2;
  1038.  
  1039.   for (cols = wantcols; *cols != '\0'; cols++) {
  1040.     switch(*cols) {
  1041.     case 'R':
  1042.       fprintf(outf, "%*d: ", fieldwidth, reqs);
  1043.       break;
  1044.     case 'r':
  1045.       pc = (reqs + 0.0) / ((total_succ_reqs + 0.0) / 10000);
  1046.       pc1 = ((int)(pc + 0.5)) / 100;     /* whole no. of %reqs */
  1047.       pc2 = ((int)(pc + 0.5)) % 100;     /* remaining 100ths. */
  1048.       if (pc1 == 100)
  1049.     fprintf(outf, "  100%%: ");
  1050.       else if (pc1 > 0 || pc2 > 0)
  1051.     fprintf(outf, "%2d.%02d%%: ", pc1, pc2);
  1052.       else
  1053.     fprintf(outf, "      : ");
  1054.       break;
  1055.     case 'B':
  1056.       if (byq)
  1057.     fprintf(outf, "%*.0lf: ", bfieldwidth, bytes / bdivider);
  1058.       break;
  1059.     case 'b':
  1060.       if (byq) {
  1061.     pc = bytes / (total_bytes / 10000);
  1062.     pc1 = ((int)(pc + 0.5)) / 100;    /* whole no. of %bytes */
  1063.     pc2 = ((int)(pc + 0.5)) % 100;    /* remaining 100ths. */
  1064.     if (pc1 == 100)
  1065.       fprintf(outf, "  100%%: ");
  1066.     else if (pc1 > 0 || pc2 > 0)
  1067.       fprintf(outf, "%2d.%02d%%: ", pc1, pc2);
  1068.     else
  1069.       fprintf(outf, "      : ");
  1070.       }
  1071.       break;
  1072.     }
  1073.   }
  1074.   if (graphtype == 'B')
  1075.     barplot(outf, (int)(ceil(bytes / (unit * bdivider))));
  1076.   else
  1077.     barplot(outf, (reqs == 0)?0:((reqs - 1) / unit) + 1);
  1078.   fprintf(outf, "\n");
  1079. }
  1080.  
  1081. /*** The status code report (very simple) ***/
  1082.  
  1083. void statusout(FILE *outf)
  1084. {
  1085.   extern int status[], statusnos[];
  1086.   extern char statusstrs[NO_STATUS][MAXSTATUSLENGTH];
  1087.   extern int aq;
  1088.  
  1089.   int fieldwidth;
  1090.   int maxreqs = 0;
  1091.   int i;
  1092.  
  1093.   for (i = 0; i < NO_STATUS; i++)
  1094.     maxreqs = MAX(maxreqs, status[i]);
  1095.  
  1096.   if (!aq) {
  1097.     fprintf(outf, "\n\n<hr>\n<h2><a NAME=\"Status\">Status Code Report</a></h2>\n\n");
  1098.     gotos(outf, 'c');
  1099.     fprintf(outf, "<pre>");
  1100.   }
  1101.   else
  1102.     fprintf(outf, "Status Code Report\n------------------\n\n");
  1103.  
  1104.   i = 10000;
  1105.   for (fieldwidth = 5; maxreqs / i >= 10; fieldwidth++)
  1106.     i *= 10;
  1107.  
  1108.   for (i = 5; i < fieldwidth; i++)
  1109.     fprintf(outf, " ");
  1110.   fprintf(outf, "#occs: no. description\n");
  1111.   for (i = 0; i < fieldwidth; i++)
  1112.     fprintf(outf, "-");
  1113.   fprintf(outf, "  ---------------\n");
  1114.  
  1115.   for (i = 0; i < NO_STATUS; i++) {
  1116.     if (status[i] > 0) {
  1117.       if (statusstrs[i][0] == '0')
  1118.     fprintf(outf, "%*d:     %s\n", fieldwidth, status[i], statusstrs[i]);
  1119.       else
  1120.     fprintf(outf, "%*d: %d %s\n", fieldwidth, status[i], statusnos[i],
  1121.         statusstrs[i]);
  1122.     }
  1123.   }
  1124.  
  1125.   if (aq)
  1126.     asciiline(outf);
  1127.   else
  1128.     fprintf(outf, "</pre>");
  1129. }
  1130.  
  1131. /*** Finally in the individual report printing, the error report ***/
  1132.  
  1133. void errout(FILE *outf, int errorder[NO_ERRS])
  1134. {
  1135.   extern int errors[NO_ERRS];
  1136.   extern char errs[NO_ERRS][MAXERRLENGTH];
  1137.   extern int errminreqs;
  1138.   extern int aq;
  1139.  
  1140.   int fieldwidth;
  1141.   int i;
  1142.  
  1143.   if (errors[errorder[0]] >= errminreqs) {    /* o/wise no report */
  1144.  
  1145.     if (!aq) {
  1146.       fprintf(outf,
  1147.           "\n\n<hr>\n<h2><a NAME=\"Error\">Error Report</a></h2>\n\n");
  1148.       gotos(outf, 'e');
  1149.       fprintf(outf, "<p>");
  1150.     }
  1151.     else
  1152.       fprintf(outf, "Error Report\n------------\n");
  1153.  
  1154.     if (errminreqs == 0)
  1155.       fprintf(outf, "Printing all possible errors, ");
  1156.     else
  1157.       fprintf(outf, "Printing all errors with at least %d occurence%s,\n",
  1158.           errminreqs, (errminreqs == 1)?"":"s");
  1159.     fprintf(outf, "  sorted by number of occurrences.");
  1160.  
  1161.     if (aq)
  1162.       fprintf(outf, "\n\n");
  1163.     else
  1164.       fprintf(outf, "<pre>");
  1165.  
  1166.     i = 10000;
  1167.     for (fieldwidth = 5; errors[errorder[0]] / i >= 10; fieldwidth++)
  1168.       i *= 10;
  1169.  
  1170.     for (i = 5; i < fieldwidth; i++)
  1171.       fprintf(outf, " ");
  1172.     fprintf(outf, "#occs: error type\n");
  1173.     for (i = 0; i < fieldwidth; i++)
  1174.       fprintf(outf, "-");
  1175.     fprintf(outf, "  ----------\n");
  1176.  
  1177.     for (i = 0; errors[errorder[i]] >= errminreqs && i < NO_ERRS; i++)
  1178.       fprintf(outf, "%*d: %s\n", fieldwidth, errors[errorder[i]],
  1179.           (errs[errorder[i]][0] == '\0')?"[unknown]":errs[errorder[i]]);
  1180.  
  1181.     if (aq)
  1182.       asciiline(outf);
  1183.     else
  1184.       fprintf(outf, "</pre>");
  1185.   }
  1186. }
  1187.  
  1188.  
  1189. /*** Now the main output function which calls all that stuff ***/
  1190.  
  1191. void output(struct genstruct *urlsorthead, struct genstruct *dirsorthead,
  1192.         struct genstruct *hostsorthead, int firstdom,
  1193.         struct genstruct *refsorthead, struct genstruct *browsorthead,
  1194.         struct genstruct *fullbrowsorthead, int errorder[])
  1195. {
  1196.   extern int dayofdate();           /* in utils.c */
  1197.   extern int minsbetween();         /* in utils.c */
  1198.   extern void int3printf();         /* in utils.c */
  1199.   extern void double3printf();      /* in utils.c */
  1200.  
  1201.   extern char outfile[];
  1202.   extern char dayname[7][4];
  1203.   extern char monthname[12][4];
  1204.   extern int monthlength[];
  1205.   extern char hostname[];
  1206.   extern char logourl[];
  1207.   extern char hosturl[];
  1208.   extern char commandname[];
  1209.   extern char headerfile[];
  1210.   extern char footerfile[];
  1211.   extern char reportorder[];
  1212.   extern flag q7, byq, refbyq, browbyq, kq, warnq;
  1213.   extern flag mback, Dback, Wback, Hback;
  1214.   extern flag xq, dq, Dq, Wq, hq, Hq, mq, Sq, rq, oq, iq, fq, bq, Bq, cq, eq;
  1215.   extern int sq, aq;
  1216.   extern char starttimestr[];
  1217.   extern struct timestruct firsttime, lasttime, oldtime, totime, starttimec;
  1218.   extern time_t starttime, stoptime;
  1219.   extern int weekbeginson;
  1220.   extern struct monthly *firstm, *lastm;
  1221.   extern struct weekly *firstw, *lastw;
  1222.   extern struct daily *firstd, *lastd;
  1223.   extern struct hourly *firsth, *lasth;
  1224.   extern int dailyreq[], hourlyreq[];
  1225.   extern double dailybytes[], hourlybytes[];
  1226.   extern int monthlyunit, weeklyunit, hourlyunit, fullhourlyunit, dailyunit;
  1227.   extern int fulldailyunit;
  1228.   extern int cachereqs, cachereqs7, corrupt_lines, other_lines;
  1229.   extern int no_urls, no_hosts, no_urls7, no_hosts7, no_new_hosts7;
  1230.   extern double total_bytes, total_bytes7;
  1231.   extern int pagewidth;
  1232.   extern int hostsortby, reqsortby, dirsortby;
  1233.   extern int refsortby, browsortby, fullbrowsortby;
  1234.   extern char hostminreqstr[], urlminreqstr[], dirminreqstr[], refminreqstr[];
  1235.   extern char browminreqstr[], fullbrowminreqstr[];
  1236.   extern char hostminbytestr[], urlminbytestr[], dirminbytestr[];
  1237.   extern char refminbytestr[], browminbytestr[], fullbrowminbytestr[];
  1238.   extern char monthgraph, daygraph, fulldaygraph, hourgraph, fullhourgraph;
  1239.   extern char weekgraph;
  1240.   extern char monthcols[], daycols[], fulldaycols[], hourcols[], weekcols[];
  1241.   extern char fullhourcols[], reqcols[], dircols[], hostcols[], refcols[];
  1242.   extern char browcols[], fullbrowcols[];
  1243.   extern char imagedir[], baseurl[];
  1244.   extern int reqtype;
  1245.   extern int status[], status7[], statusnos[];
  1246.   extern int dir_max_reqs, host_max_reqs, url_max_reqs,
  1247.              ref_max_reqs, brow_max_reqs, fullbrow_max_reqs;
  1248.   extern double dir_max_bytes, host_max_bytes, url_max_bytes;
  1249.  
  1250.   FILE *outf;       /* the output file */
  1251.   int totalmins;    /* between first and last entries analysed */
  1252.   int fieldwidth;   /* Width we require to print #reqs in */
  1253.   int bfieldwidth;  /* #bytes ditto */
  1254.   char bprefix[2];  /* kilo, Mega, etc. */
  1255.   int graphwidth;   /* the width left for a graph after columns written */
  1256.   struct monthly *mp;
  1257.   struct daily *dp;
  1258.   struct weekly *wp;
  1259.   struct hourly *hp;
  1260.   int maxreq;       /* within a particular date report */
  1261.   double maxbytes;
  1262.   double bdivider;
  1263.   int year, monthno, date;
  1264.   flag finished;
  1265.   int i, j, firsti, lasti;
  1266.   char *ro;
  1267.   char tempstr[MAXSTRINGLENGTH];
  1268.   FILE *tempf;
  1269.  
  1270.   bprefix[0] = '\0';
  1271.   bprefix[1] = '\0';
  1272.  
  1273.   total_succ_reqs = cachereqs;
  1274.   total_fail_reqs = 0;
  1275.   total_other_reqs = 0;
  1276.   total_succ_reqs7 = cachereqs7;
  1277.   total_fail_reqs7 = 0;
  1278.   total_other_reqs7 = 0;
  1279.   for (i = 0; i < NO_STATUS; i++) {
  1280.     if (statusnos[i] <= 299 || statusnos[i] == 304) {
  1281.       total_succ_reqs += status[i];
  1282.       total_succ_reqs7 += status7[i];
  1283.     }
  1284.     else if (statusnos[i] <= 399) {
  1285.       total_other_reqs += status[i];
  1286.       total_other_reqs7 += status7[i];
  1287.     }
  1288.     else {
  1289.       total_fail_reqs += status[i];
  1290.       total_fail_reqs7 += status7[i];
  1291.     }
  1292.   }
  1293.  
  1294.   if (STREQ(outfile, "stdout"))
  1295.     outf = stdout;
  1296.  
  1297.   else if ((outf = fopen(outfile, "w")) == NULL) {
  1298.     fprintf(stderr, "%s: Error: failed to open output file %s for writing.\n",
  1299.         commandname, outfile);
  1300.     exit(ERR);  /* shouldn't get here because also tested at the beginning */
  1301.   }             /* (unless it's vanished in the meantime or something) */
  1302.  
  1303.   if (aq == CACHE)
  1304.     fprintf(outf,
  1305.         "CACHE type 1 produced by analog%s. Do not modify or delete!",
  1306.         VERSION);
  1307.   else {
  1308.     if (!aq) {
  1309.       fprintf(outf, "<html>\n<head><title>Web Server Statistics for ");
  1310.       htmlfprintf(outf, hostname);
  1311.       fprintf(outf, "</title></head>\n");
  1312.       fprintf(outf, "<body>\n<h1><a NAME=\"Top\">");
  1313.       if (!STREQ(logourl, "none")) {
  1314.     fprintf(outf, "<IMG src=\"");
  1315.     htmlfprintf(outf, logourl);
  1316.     fprintf(outf, "\" alt=\"\"> ");
  1317.       }
  1318.       if (hosturl[0] == '-') {
  1319.     fprintf(outf, "Web Server Statistics</a> for ");
  1320.     htmlfprintf(outf, hostname);
  1321.       }
  1322.       else {
  1323.     fprintf(outf, "Web Server Statistics</a> for <a HREF=\"");
  1324.     htmlfprintf(outf, hosturl);
  1325.     fprintf(outf, "\">");
  1326.     htmlfprintf(outf, hostname);
  1327.     fprintf(outf, "</a>");
  1328.       }
  1329.       fprintf(outf, "</h1>\n\n");
  1330.     }
  1331.     else {
  1332.       fprintf(outf, "Web Server Statistics for %s\n", hostname);
  1333.       fprintf(outf, "==========================");
  1334.       for (i = (int)strlen(hostname); i > 0; i--)
  1335.     fprintf(outf, "=");
  1336.       fprintf(outf, "\n");
  1337.     }
  1338.     
  1339.     /* insert header file */
  1340.     
  1341.     headerfile[MAXSTRINGLENGTH - 5] = '\0';  /* for safety */
  1342.     
  1343.     if (!STREQ(headerfile, "none")) {
  1344.       if ((tempf = fopen(headerfile, "r")) == NULL) {
  1345.     if (warnq)
  1346.       fprintf(stderr,
  1347.           "%s: Warning: Failed to open headerfile %s: ignoring it.\n",
  1348.           commandname, headerfile);
  1349.       }
  1350.       else {  /* can open header file */
  1351.     if (!aq)
  1352.       fprintf(outf, "<hr>");
  1353.     else
  1354.       fprintf(outf, "\n");
  1355.     
  1356.     while(fgets(tempstr, MAXLINELENGTH, tempf) != NULL)
  1357.       fprintf(outf, "%s", tempstr);
  1358.     fclose(tempf);
  1359.     if (tempstr[(int)strlen(tempstr) - 1] != '\n')
  1360.       fprintf(outf, "\n");
  1361.     
  1362.       if (aq) {
  1363.     for (i = 0; i < pagewidth; i++)
  1364.       fprintf(outf, "-");
  1365.       }
  1366.     
  1367.       fprintf(outf, "\n");
  1368.     
  1369.       }
  1370.     }
  1371.   }
  1372.  
  1373.   /* Summary statistics */
  1374.  
  1375.   if (xq) {
  1376.  
  1377.     if (!aq)
  1378.       fprintf(outf, "<hr>");
  1379.  
  1380.     fprintf(outf,
  1381.         "\nProgram started at %c%c%c-%c%c-%c%c%c-%c%c%c%c %c%c:%c%c local time.\n",
  1382.        starttimestr[0], starttimestr[1], starttimestr[2],
  1383.        (starttimestr[8]==' ')?'0':starttimestr[8], starttimestr[9],
  1384.        starttimestr[4], starttimestr[5], starttimestr[6],
  1385.        starttimestr[20], starttimestr[21], starttimestr[22],
  1386.        starttimestr[23],
  1387.        starttimestr[11], starttimestr[12],
  1388.        starttimestr[14], starttimestr[15]);
  1389.   
  1390.     if (firsttime.code > oldtime.code)
  1391.       q7 = OFF;
  1392.   
  1393.     if (total_succ_reqs > 0) {
  1394.       totalmins = minsbetween(firsttime.date, firsttime.monthno, firsttime.year,
  1395.                   firsttime.hr, firsttime.min,
  1396.                   lasttime.date, lasttime.monthno, lasttime.year,
  1397.                   lasttime.hr, lasttime.min) + 1;
  1398.       if (!aq)
  1399.     fprintf(outf, "<br>");
  1400.       fprintf(outf,
  1401.           "Analysed requests from %s-%02d-%s-%d %02d:%02d to %s-%02d-%s-%d %02d:%02d\n  (%.1f days).\n\n",
  1402.          dayname[dayofdate(firsttime.date,
  1403.                    firsttime.monthno, firsttime.year)],
  1404.          firsttime.date, monthname[firsttime.monthno], firsttime.year,
  1405.          firsttime.hr, firsttime.min,
  1406.          dayname[dayofdate(lasttime.date, lasttime.monthno,
  1407.                    lasttime.year)],
  1408.          lasttime.date, monthname[lasttime.monthno], lasttime.year,
  1409.          lasttime.hr, lasttime.min,
  1410.          (double)totalmins / 1440.0);
  1411.     }
  1412.  
  1413.     if (!aq)
  1414.       fprintf(outf, "<p><b>Total completed requests:</b> ");
  1415.     else
  1416.       fprintf(outf, "Total completed requests: ");
  1417.     int3printf(outf, total_succ_reqs);
  1418.     if (q7) {
  1419.       fprintf(outf, " (");
  1420.       int3printf(outf, total_succ_reqs7);
  1421.       fprintf(outf, ")");
  1422.     }
  1423.     if (totalmins > 30) {
  1424.       if (!aq)
  1425.     fprintf(outf, "\n<br><b>Average completed requests per day:</b> ");
  1426.       else
  1427.     fprintf(outf, "\nAverage completed requests per day: ");
  1428.       if (total_succ_reqs < 2)
  1429.     fprintf(outf, "0");
  1430.       else
  1431.     double3printf(outf, ((double)(total_succ_reqs - 1)) * 1440.0 / (totalmins + 0.0));
  1432.       if (q7) {
  1433.     fprintf(outf, " (");
  1434.     int3printf(outf, total_succ_reqs7 / 7);
  1435.     fprintf(outf, ")");
  1436.       }
  1437.     }
  1438.     if (total_fail_reqs > 0) {
  1439.       if (!aq)
  1440.     fprintf(outf, "\n<br><b>Total failed requests:</b> ");
  1441.       else
  1442.     fprintf(outf, "\nTotal failed requests: ");
  1443.       int3printf(outf, total_fail_reqs);
  1444.       if (q7) {
  1445.     fprintf(outf, " (");
  1446.     int3printf(outf, total_fail_reqs7);
  1447.     fprintf(outf, ")");
  1448.       }
  1449.     }
  1450.     if (total_other_reqs > 0) {
  1451.       if (!aq)
  1452.     fprintf(outf, "\n<br><b>Total redirected requests:</b> ");
  1453.       else
  1454.     fprintf(outf, "\nTotal redirected requests: ");
  1455.       int3printf(outf, total_other_reqs);
  1456.       if (q7) {
  1457.     fprintf(outf, " (");
  1458.     int3printf(outf, total_other_reqs7);
  1459.     fprintf(outf, ")");
  1460.       }
  1461.     }
  1462.     if (rq) {   /* These data are not collected o/wise (rq => this > 0) */
  1463.       if (!aq)
  1464.     fprintf(outf, "\n<br><b>Number of distinct files requested:</b> ");
  1465.       else
  1466.     fprintf(outf, "\nNumber of distinct files requested: ");
  1467.       int3printf(outf, no_urls);
  1468.       if (q7) {
  1469.     fprintf(outf, " (");
  1470.     int3printf(outf, no_urls7);
  1471.     fprintf(outf, ")");
  1472.       }
  1473.     }
  1474.     if ((sq == ON || sq == APPROX) && no_hosts > 0) {
  1475.       if (!aq)
  1476.     fprintf(outf, "\n<br><b>%sumber of distinct hosts served:</b> ",
  1477.            (sq == ON)?"N":"Approximate n");
  1478.       else
  1479.     fprintf(outf, "\n%sumber of distinct hosts served: ",
  1480.            (sq == ON)?"N":"Approximate n");
  1481.       int3printf(outf, no_hosts);
  1482.       if (q7) {
  1483.     fprintf(outf, " (");
  1484.     int3printf(outf, no_hosts7);
  1485.     fprintf(outf, ")");
  1486.     if (!aq)
  1487.       fprintf(outf,
  1488.           "\n<br><b>%sumber of new hosts served in last 7 days:</b> ",
  1489.          (sq == ON)?"N":"Approximate n");
  1490.     else
  1491.       fprintf(outf, "\n%sumber of new hosts served in last 7 days: ",
  1492.          (sq == ON)?"N":"Approximate n");
  1493.     int3printf(outf, no_new_hosts7);
  1494.       }
  1495.     }
  1496.     if (corrupt_lines > 0) {
  1497.       if (!aq)
  1498.     fprintf(outf, "\n<br><b>Corrupt logfile lines:</b> ");
  1499.       else
  1500.     fprintf(outf, "\nCorrupt logfile lines: ");
  1501.       int3printf(outf, corrupt_lines);
  1502.     }
  1503.     if (other_lines > 0) {
  1504.       if (!aq)
  1505.     fprintf(outf, "\n<br><b>Unwanted logfile entries:</b> ");
  1506.       else
  1507.     fprintf(outf, "\nUnwanted logfile entries: ");
  1508.       int3printf(outf, other_lines);
  1509.     }
  1510.     if (byq) {
  1511.       if (!aq)
  1512.     fprintf(outf, "\n<br><b>Total data transferred:</b> ");
  1513.       else
  1514.     fprintf(outf, "\nTotal data transferred: ");
  1515.       bdivider = finddivider(total_bytes, bprefix);
  1516.       double3printf(outf, ROUND(total_bytes / bdivider));
  1517.       fprintf(outf, " %sbytes", bprefix);
  1518.       if (q7) {
  1519.     fprintf(outf, " (");
  1520.     bdivider = finddivider(total_bytes7, bprefix);
  1521.     double3printf(outf, ROUND(total_bytes7 / bdivider));
  1522.     fprintf(outf, " %sbytes)", bprefix);
  1523.       }
  1524.       if (totalmins > 30) {
  1525.     if (!aq)
  1526.       fprintf(outf, "\n<br><b>Average data transferred per day:</b> ");
  1527.     else
  1528.       fprintf(outf, "\nAverage data transferred per day: ");
  1529.     bdivider = finddivider((total_bytes * 1440) / (totalmins + 0.0),
  1530.                    bprefix);
  1531.     double3printf(outf,
  1532.           ROUND((total_bytes * 1440) / (totalmins + 0.0) / bdivider));
  1533.     fprintf(outf, " %sbytes", bprefix);
  1534.     if (q7) {
  1535.       fprintf(outf, " (");
  1536.       bdivider = finddivider(total_bytes7 / 7.0, bprefix);
  1537.       double3printf(outf, ROUND(total_bytes7 / 7.0 / bdivider));
  1538.       fprintf(outf, " %sbytes)", bprefix);
  1539.     }
  1540.       }
  1541.     }
  1542.     if (q7) {
  1543.       if (!aq)
  1544.     fprintf(outf, "\n<br>");
  1545.       else
  1546.     fprintf(outf, "\n");
  1547.       fprintf(outf, "(Figures in parentheses refer to the ");
  1548.       if (starttimec.code > totime.code)
  1549.     fprintf(outf, "7 days to %02d-%s-%4d).", totime.date,
  1550.         monthname[totime.monthno], totime.year);
  1551.       else
  1552.     fprintf(outf, "last 7 days).");
  1553.     }
  1554.  
  1555.     if (!aq && (mq || Wq || dq || Dq || hq || oq || Sq || iq || rq))
  1556.       gotos(outf, 'z');
  1557.     if (aq) {
  1558.       fprintf(outf, "\n");
  1559.       asciiline(outf);
  1560.     }
  1561.  
  1562.   }   /* end if xq */
  1563.  
  1564.   else if (aq == ASCII)
  1565.     printf("\n");
  1566.  
  1567.   /* Now for the rest of the reports, in reportorder order */
  1568.  
  1569.   for (ro = reportorder; *ro != '\0'; ro++) {
  1570.  
  1571.     switch(*ro) {
  1572.  
  1573.     case 'm':    /* Monthly report */
  1574.  
  1575.       if (mq) {
  1576.  
  1577.     maxreq = 0;
  1578.     maxbytes = 0.0;
  1579.     finished = FALSE;
  1580.     for (mp = mback?lastm:firstm; !finished; mp = mp -> next) {
  1581.       for (i = 0; i < 12; i++) {
  1582.         maxreq = MAX(maxreq, mp -> reqs[i]);
  1583.         maxbytes = MAX(maxbytes, mp -> bytes[i]);
  1584.       }
  1585.       if (mp == (mback?firstm:lastm))
  1586.         finished = TRUE;
  1587.     }
  1588.  
  1589.     datehead(outf, maxreq, maxbytes, monthcols, &monthgraph,
  1590.          "Monthly", "Monthly Report", "   month", 'm', &monthlyunit,
  1591.          &fieldwidth, &bfieldwidth, &graphwidth, &bdivider);
  1592.  
  1593.     finished = FALSE;
  1594.     year = (mback?lasttime:firsttime).year;
  1595.     for (mp = mback?lastm:firstm; !finished; mp = mp -> next) {
  1596.       if (mp == firstm) {
  1597.         firsti = firsttime.monthno;
  1598.         if (mback)
  1599.           finished = TRUE;
  1600.       }
  1601.       else
  1602.         firsti = 0;
  1603.       if (mp == lastm) {
  1604.         lasti = lasttime.monthno;
  1605.         if (!mback)
  1606.           finished = TRUE;
  1607.       }
  1608.       else
  1609.         lasti = 11;
  1610.       for (i = mback?lasti:firsti; mback?(i >= firsti):(i <= lasti);
  1611.            i += mback?(-1):1) {  /* run through months in chosen order */
  1612.         fprintf(outf, "%s %d: ", monthname[i], year);
  1613.         dateline(outf, mp -> reqs[i], mp -> bytes[i], monthcols,
  1614.              monthgraph, fieldwidth, bfieldwidth, monthlyunit,
  1615.              bdivider);
  1616.       }
  1617.       year += mback?(-1):1;
  1618.     }
  1619.     
  1620.     if (aq)
  1621.       asciiline(outf);
  1622.     else
  1623.       fprintf(outf, "</tt></pre>");
  1624.     
  1625.       }
  1626.  
  1627.       break;
  1628.       
  1629.     case 'W':      /* Weekly report */
  1630.  
  1631.       if (Wq) {
  1632.  
  1633.     maxreq = 0;
  1634.     maxbytes = 0.0;
  1635.     finished = FALSE;
  1636.     for (wp = Wback?lastw:firstw; !finished; wp = wp -> next) {
  1637.       maxreq = MAX(maxreq, wp -> reqs);
  1638.       maxbytes = MAX(maxbytes, wp -> bytes);
  1639.       if (wp == (Wback?firstw:lastw))
  1640.         finished = TRUE;
  1641.     }
  1642.  
  1643.     datehead(outf, maxreq, maxbytes, weekcols, &weekgraph,
  1644.          "Weekly", "Weekly Report", "week beg.", 'W', &weeklyunit,
  1645.          &fieldwidth, &bfieldwidth, &graphwidth, &bdivider);
  1646.  
  1647.     finished = FALSE;
  1648.     for (wp = Wback?lastw:firstw; !finished; wp = wp -> next) {
  1649.       fprintf(outf, "%2d/%s/%02d: ", wp -> start.date,
  1650.          monthname[wp -> start.monthno], wp -> start.year % 100);
  1651.       dateline(outf, wp -> reqs, wp -> bytes, weekcols, weekgraph,
  1652.            fieldwidth, bfieldwidth, weeklyunit, bdivider);
  1653.       if (wp == (Wback?firstw:lastw))
  1654.         finished = TRUE;
  1655.       
  1656.     }     /* end running through weeks */
  1657.  
  1658.     if (aq)
  1659.       asciiline(outf);
  1660.     else
  1661.       fprintf(outf, "</tt></pre>");
  1662.     
  1663.       }   /* end if Wq */
  1664.  
  1665.       break;
  1666.  
  1667.     case 'd':      /* Daily summary */
  1668.  
  1669.       if (dq) {
  1670.     
  1671.     maxreq = 0;
  1672.     maxbytes = 0.0;
  1673.     for (i = 0; i <= 6; i++) {
  1674.       maxreq = MAX(maxreq, dailyreq[i]);
  1675.       maxbytes = MAX(maxbytes, dailybytes[i]);
  1676.     }
  1677.     
  1678.     datehead(outf, maxreq, maxbytes, daycols, &daygraph,
  1679.          "Daily", "Daily Summary", "day", 'd', &dailyunit,
  1680.          &fieldwidth, &bfieldwidth, &graphwidth, &bdivider);
  1681.  
  1682.     for(i = 0; i <= 6; i++) {
  1683.       j = (weekbeginson + i) % 7;
  1684.       fprintf(outf, "%s: ", dayname[j]);
  1685.       dateline(outf, dailyreq[j], dailybytes[j], daycols, daygraph,
  1686.            fieldwidth, bfieldwidth, dailyunit, bdivider);
  1687.     }
  1688.     
  1689.     if (aq)
  1690.       asciiline(outf);
  1691.     else
  1692.       fprintf(outf, "</tt></pre>");
  1693.     
  1694.       }
  1695.  
  1696.       break;
  1697.       
  1698.     case 'D':       /* Full daily report */
  1699.  
  1700.       if (Dq) {
  1701.  
  1702.     maxreq = 0;
  1703.     maxbytes = 0.0;
  1704.     finished = FALSE;
  1705.     for (dp = Dback?lastd:firstd; !finished; dp = dp -> next) {
  1706.       for (i = 0; i < 31; i++) {
  1707.         maxreq = MAX(maxreq, dp -> reqs[i]);
  1708.         maxbytes = MAX(maxbytes, dp -> bytes[i]);
  1709.       }
  1710.       if (dp == (Dback?firstd:lastd))
  1711.         finished = TRUE;
  1712.     }
  1713.  
  1714.     datehead(outf, maxreq, maxbytes, fulldaycols, &fulldaygraph,
  1715.          "FullDaily", "Daily Report", "     date", 'D',
  1716.          &fulldailyunit, &fieldwidth, &bfieldwidth, &graphwidth,
  1717.          &bdivider);
  1718.     
  1719.     finished = FALSE;
  1720.     year = (Dback?lasttime:firsttime).year;
  1721.     monthno = (Dback?lasttime:firsttime).monthno;
  1722.     for (dp = Dback?lastd:firstd; !finished; dp = dp -> next) {
  1723.       if (dp == firstd) {
  1724.         firsti = firsttime.date - 1;
  1725.         if (Dback)
  1726.           finished = TRUE;
  1727.       }
  1728.       else
  1729.         firsti = 0;
  1730.       if (dp == lastd) {
  1731.         lasti = lasttime.date - 1;
  1732.         if (!Dback)
  1733.           finished = TRUE;
  1734.       }
  1735.       else
  1736.         lasti = monthlength[monthno] + ISLEAPFEB(monthno, year) - 1;
  1737.       for (i = Dback?lasti:firsti; Dback?(i >= firsti):(i <= lasti);
  1738.            i += Dback?(-1):1) {  /* run through days in chosen order */
  1739.         fprintf(outf, "%2d/%s/%02d: ", i + 1, monthname[monthno],
  1740.             year % 100);
  1741.         dateline(outf, dp -> reqs[i], dp -> bytes[i], fulldaycols,
  1742.              fulldaygraph, fieldwidth, bfieldwidth, fulldailyunit,
  1743.              bdivider);
  1744.         if (((dayofdate(i + 1, monthno, year) + (!Dback)) % 7 ==
  1745.          weekbeginson) && !(finished && i == (Dback?firsti:lasti)))
  1746.           fprintf(outf, "\n");
  1747.                          /* extra blank line after each week (not last) */
  1748.       }
  1749.  
  1750.       if (Dback) {
  1751.         if ((--monthno) == -1) {
  1752.           monthno = 11;
  1753.           --year;
  1754.         }
  1755.       }
  1756.       else {
  1757.         if ((++monthno) == 12) {
  1758.           monthno = 0;
  1759.           ++year;
  1760.         }
  1761.       }
  1762.       
  1763.     }     /* end running through dp's */
  1764.  
  1765.     if (aq)
  1766.       asciiline(outf);
  1767.     else
  1768.       fprintf(outf, "</tt></pre>");
  1769.     
  1770.       }   /* end if Dq */
  1771.  
  1772.       break;
  1773.  
  1774.     case 'H':       /* Full hourly report */
  1775.  
  1776.       if (Hq) {
  1777.  
  1778.     maxreq = 0;
  1779.     maxbytes = 0.0;
  1780.     finished = FALSE;
  1781.     for (hp = Hback?lasth:firsth; !finished; hp = hp -> next) {
  1782.       for (i = 0; i < 24; i++) {
  1783.         maxreq = MAX(maxreq, hp -> reqs[i]);
  1784.         maxbytes = MAX(maxbytes, hp -> bytes[i]);
  1785.       }
  1786.       if (hp == (Hback?firsth:lasth))
  1787.         finished = TRUE;
  1788.     }
  1789.  
  1790.     if (aq != CACHE)
  1791.       datehead(outf, maxreq, maxbytes, fullhourcols, &fullhourgraph,
  1792.            "FullHourly", "Hourly Report", "     date:hr", 'H',
  1793.            &fullhourlyunit, &fieldwidth, &bfieldwidth, &graphwidth,
  1794.            &bdivider);
  1795.     
  1796.     finished = FALSE;
  1797.     year = (Hback?lasttime:firsttime).year;
  1798.     monthno = (Hback?lasttime:firsttime).monthno;
  1799.     date = (Hback?lasttime:firsttime).date;
  1800.     for (hp = Hback?lasth:firsth; !finished; hp = hp -> next) {
  1801.       if (hp == firsth) {
  1802.         firsti = firsttime.hr;
  1803.         if (Hback)
  1804.           finished = TRUE;
  1805.       }
  1806.       else
  1807.         firsti = 0;
  1808.       if (hp == lasth) {
  1809.         lasti = lasttime.hr;
  1810.         if (!Hback)
  1811.           finished = TRUE;
  1812.       }
  1813.       else
  1814.         lasti = 23;
  1815.       for (i = Hback?lasti:firsti; Hback?(i >= firsti):(i <= lasti);
  1816.            i += Hback?(-1):1) {  /* run through hours in chosen order */
  1817.         if (aq == CACHE) {
  1818.           if (i == 0 || (hp == firsth && i == firsti))
  1819.         fprintf(outf, "\n%d%02d%02d%02d", year, monthno + 1, date, i);
  1820.           fprintf(outf, ":%d:%.0lf", hp -> reqs[i], hp -> bytes[i]);
  1821.         }
  1822.         else {
  1823.           fprintf(outf, "%2d/%s/%02d:%02d: ", date, monthname[monthno],
  1824.               year % 100, i);
  1825.           dateline(outf, hp -> reqs[i], hp -> bytes[i], fullhourcols,
  1826.                fullhourgraph, fieldwidth, bfieldwidth, fullhourlyunit,
  1827.                bdivider);
  1828.           if (i == (Hback?0:23) && !finished)
  1829.         fprintf(outf, "\n");
  1830.           /* extra blank line after each day (not last) */
  1831.         }
  1832.       }
  1833.  
  1834.       if (Hback) {
  1835.         if ((--date) == 0) {
  1836.           if ((--monthno) == -1) {
  1837.         monthno = 11;
  1838.         --year;
  1839.           }
  1840.           date = monthlength[monthno] + ISLEAPFEB(monthno, year);
  1841.         }
  1842.       }
  1843.       else {
  1844.         if ((++date) > monthlength[monthno] + ISLEAPFEB(monthno, year)) {
  1845.           if ((++monthno) == 12) {
  1846.         monthno = 0;
  1847.         ++year;
  1848.           }
  1849.           date = 1;
  1850.         }
  1851.       }
  1852.       
  1853.     }     /* end running through hp's */
  1854.  
  1855.     if (aq == CACHE)
  1856.       fprintf(outf, ":*\n");
  1857.     else if (aq)
  1858.       asciiline(outf);
  1859.     else if (!aq)
  1860.       fprintf(outf, "</tt></pre>");
  1861.     
  1862.       }   /* end if Hq */
  1863.     
  1864.       break;
  1865.  
  1866.     case 'h': /* Hourly summary */
  1867.  
  1868.       if (hq) {
  1869.  
  1870.     maxreq = 0;
  1871.     maxbytes = 0.0;
  1872.     for (i = 0; i <= 23; i++) {
  1873.       maxreq = MAX(maxreq, hourlyreq[i]);
  1874.       maxbytes = MAX(maxbytes, hourlybytes[i]);
  1875.     }
  1876.  
  1877.     datehead(outf, maxreq, maxbytes, hourcols, &hourgraph, "Hourly",
  1878.          "Hourly Summary", "hr", 'h', &hourlyunit, &fieldwidth,
  1879.          &bfieldwidth, &graphwidth, &bdivider);
  1880.     
  1881.     for(i = 0; i <= 23; i++) {
  1882.       fprintf(outf, "%2d: ", i);
  1883.       dateline(outf, hourlyreq[i], hourlybytes[i], hourcols, hourgraph,
  1884.            fieldwidth, bfieldwidth, hourlyunit, bdivider);
  1885.     }
  1886.     
  1887.     if (aq)
  1888.       asciiline(outf);
  1889.     else
  1890.       fprintf(outf, "</tt></pre>");
  1891.     
  1892.       }
  1893.       
  1894.       break;
  1895.  
  1896.     case 'o':    /* Domain report */
  1897.  
  1898.       if (oq)
  1899.     domout(outf, firstdom);
  1900.     
  1901.       break;
  1902.  
  1903.     case 'S':    /* Host report */
  1904.    
  1905.       if (Sq)
  1906.      genout(outf, hostsorthead, hostsortby, hostminreqstr, hostminbytestr,
  1907.            host_max_reqs, host_max_bytes, hostcols,
  1908.            "Host", "Host Report", "host", "hosts", 'S',
  1909.            hostsortby == ALPHABETICAL, byq, OFF, "");
  1910.       break;
  1911.     
  1912.     case 'i':   /* Directory report */
  1913.    
  1914.       if (iq)
  1915.     genout(outf, dirsorthead, dirsortby, dirminreqstr, dirminbytestr,
  1916.            dir_max_reqs, dir_max_bytes, dircols, "Directory",
  1917.            "Directory Report", "directory", "directories", 'i', FALSE,
  1918.            byq, OFF, "");
  1919.       break;
  1920.  
  1921.     case 'r':    /* Request report */
  1922.       
  1923.       if (rq) {
  1924.     if (aq)
  1925.       kq = 0;    /* no links in ASCII output! */
  1926.     else if (reqtype == PAGES)
  1927.       kq = 2;    /* If only printing pages, any linked = all linked */
  1928.     genout(outf, urlsorthead, reqsortby, urlminreqstr, urlminbytestr,
  1929.            url_max_reqs, url_max_bytes, reqcols, "Request", 
  1930.            "Request Report", (reqtype == PAGES)?"page":"file",
  1931.            (reqtype == PAGES)?"pages":"files", 'r', FALSE, byq, kq,
  1932.            baseurl);
  1933.       }
  1934.       break;
  1935.  
  1936.     case 'f':    /* Referer report */
  1937.  
  1938.       if (fq)
  1939.     genout(outf, refsorthead, refsortby, refminreqstr, refminbytestr,
  1940.            ref_max_reqs, 0, refcols, "Referer", "Referer Report",
  1941.            "refering URL", "refering URLs", 'f', FALSE, refbyq, !aq, "");
  1942.       break;
  1943.  
  1944.     case 'b':    /* Browser summary */
  1945.  
  1946.       if (bq)
  1947.     genout(outf, browsorthead, browsortby, browminreqstr, browminbytestr,
  1948.            brow_max_reqs, 0, browcols, "Browser", "Browser Summary",
  1949.            "browser", "browsers", 'b', FALSE, browbyq, OFF, "");
  1950.       break;
  1951.  
  1952.     case 'B':    /* Full browser report */
  1953.  
  1954.       if (Bq)
  1955.     genout(outf, fullbrowsorthead, fullbrowsortby, fullbrowminreqstr,
  1956.            fullbrowminbytestr, fullbrow_max_reqs, 0, fullbrowcols,
  1957.            "FullBrowser", "Browser Report", "browser", "browsers", 'B',
  1958.            FALSE, browbyq, OFF, "");
  1959.       break;
  1960.  
  1961.     case 'c':
  1962.  
  1963.       if (cq)
  1964.     statusout(outf);
  1965.       break;
  1966.  
  1967.     case 'e':
  1968.  
  1969.       if (eq)
  1970.     errout(outf, errorder);
  1971.       break;
  1972.  
  1973.     }    /* end switch */
  1974.   }      /* end for ro */
  1975.  
  1976.  
  1977.   /*** Bit at the bottom of the page ***/
  1978.  
  1979.   if (aq != CACHE) {
  1980.     if (!aq)
  1981.       fprintf(outf, "\n\n<hr>\n<i>This analysis was produced by <a HREF=\"http://www.statslab.cam.ac.uk/~sret1/analog/\">analog%s</a>.\n", VERSION);
  1982.     else
  1983.       fprintf(outf, "This analysis was produced by analog%s.\n", VERSION);
  1984.  
  1985.     time(&stoptime);
  1986.   
  1987.     stoptime -= starttime;   /* so now measures elapsed time */
  1988.  
  1989.     if (stoptime == 0) {
  1990.       if (!aq)
  1991.     fprintf(outf, "<br><b>Running time:</b> Less than 1 second.</i>\n");
  1992.       else
  1993.     fprintf(outf, "Running time: Less than 1 second.\n");
  1994.     }
  1995.  
  1996.     else if (stoptime < 60) {
  1997.       if (!aq)
  1998.     fprintf(outf, "<br><b>Running time:</b> %ld second%s.</i>\n",
  1999.         stoptime, (stoptime == 1)?"":"s");
  2000.       else
  2001.     fprintf(outf, "Running time: %ld second%s.\n",
  2002.         stoptime, (stoptime == 1)?"":"s");
  2003.     }
  2004.   
  2005.     else {
  2006.       if (!aq)
  2007.     fprintf(outf,
  2008.         "<br><b>Running time:</b> %ld minute%s, %ld second%s.</i>\n",
  2009.         stoptime / 60, (stoptime / 60 == 1)?"":"s",
  2010.         stoptime % 60, (stoptime % 60 == 1)?"":"s");
  2011.       else
  2012.     fprintf(outf, "Running time: %ld minute%s, %ld second%s.\n",
  2013.         stoptime / 60, (stoptime / 60 == 1)?"":"s",
  2014.         stoptime % 60, (stoptime % 60 == 1)?"":"s");
  2015.     }
  2016.   
  2017.     if (!aq && (mq || Wq || dq || Dq || hq || oq || Sq || iq || rq)) {
  2018.       gotos(outf, '\0');
  2019.     }
  2020.  
  2021.     /* Finally, insert footer file */
  2022.  
  2023.     footerfile[MAXSTRINGLENGTH - 5] = '\0';  /* for safety */
  2024.  
  2025.     if (!STREQ(footerfile, "none")) {
  2026.       if ((tempf = fopen(footerfile, "r")) == NULL) {
  2027.     if (warnq)
  2028.       fprintf(stderr,
  2029.           "%s: Warning: Failed to open footer file %s: ignoring it.\n",
  2030.           commandname, footerfile);
  2031.       }
  2032.       else {  /* can open footer file */
  2033.     if (!aq)
  2034.       fprintf(outf, "<hr>");
  2035.     else {
  2036.       for (i = 0; i < pagewidth; i++)
  2037.         fprintf(outf, "-");
  2038.     }
  2039.     fprintf(outf, "\n\n");
  2040.     fflush(stdout);
  2041.  
  2042.     while(fgets(tempstr, MAXLINELENGTH, tempf) != NULL)
  2043.       fprintf(outf, "%s", tempstr);
  2044.     fclose(tempf);
  2045.     if (tempstr[(int)strlen(tempstr) - 1] != '\n')
  2046.       fprintf(outf, "\n");
  2047.  
  2048.     fprintf(outf, "\n");
  2049.       }
  2050.     }
  2051.  
  2052.     if (!aq) {
  2053.       if (STREQ(headerfile, "none") && STREQ(footerfile, "none")) {
  2054.     fprintf(outf,
  2055.         "<P> <A HREF=\"http://www.webtechs.com/html-val-svc/\">\n");
  2056.     fprintf(outf, "<IMG SRC=\"");
  2057.     htmlfprintf(outf, imagedir);
  2058.     fprintf(outf, "html2.gif\"\n");
  2059.     fprintf(outf, "ALT=\"HTML 2.0 Compliant!\"></A>\n");
  2060.       }
  2061.       fprintf(outf, "\n</body>\n</html>\n");
  2062.     }
  2063.   }
  2064.  
  2065.   fclose(outf);
  2066.  
  2067. }
  2068.